#include <iostream>
#include <vector>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include "LockGuard.hpp"

using namespace std;

#define NUM 4

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

class threadDate
{
public:
    threadDate(int num /*, pthread_mutex_t* lock*/)
    {
        _threadname = "thread-" + to_string(num);
        //_lock = lock;
    }

public:
    string _threadname;
    // pthread_mutex_t* _lock;
};

int tickets = 2000;

void *getTicket(void *args)
{
    threadDate *td = static_cast<threadDate *>(args);
    const char *name = td->_threadname.c_str();

    while (true)
    {
        LockGuard lockguard(&lock);
        {

            // pthread_mutex_lock(&lock);
            // pthread_mutex_lock(td->_lock);
            if (tickets > 0)
            {
                usleep(1000);
                printf("%s get a ticket: %d\n", name, tickets);
                tickets--;
                // pthread_mutex_unlock(td->_lock);
                // pthread_mutex_unlock(&lock);
            }
            else
            {
                // pthread_mutex_unlock(td->_lock);
                // pthread_mutex_unlock(&lock);
                break;
            }
        }
        usleep(13);
    }

    printf("%s --- quit\n", name);
    return nullptr;
}

int main()
{
    vector<pthread_t> tids;
    vector<threadDate *> thread_date;

    // pthread_mutex_t lock;
    // pthread_mutex_init(&lock, nullptr);
    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        threadDate *td = new threadDate(i /*, &lock*/);
        thread_date.push_back(td);
        pthread_create(&tid, nullptr, getTicket, thread_date[i - 1]);
        tids.push_back(tid);
    }

    for (auto thread : tids)
    {
        pthread_join(thread, nullptr);
    }

    for (auto td : thread_date)
    {
        delete td;
    }

    // pthread_mutex_destroy(&lock);
    return 0;
}

// #define NUM 10

// int* p = nullptr;
// __thread int g_val = 10; // 线程的局部存储，只能修饰内置类型，线程的私有全局变量

// class pthreadDate
// {
// public:
//     string _pthreadname;
// };

// void initThread(pthreadDate* td, int num)
// {
//     td->_pthreadname = "thread-" + to_string(num);
// }

// string toHex(int tid)
// {
//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", tid);
//     return buffer;
// }

// void* threadRoutine(void* args)
// {
//     pthreadDate* td = static_cast<pthreadDate*>(args);
//     string tid = toHex(pthread_self());
//     int pid = getpid();

//     int test_i = 0;
//     if(td->_pthreadname == "thread-2")
//         p = &test_i;

//     int i = 0;
//     while(i < 10)
//     {
//         cout << "threadname: " << td->_pthreadname << ", tid: "
//             << tid << ", pid: " << pid << ", g_val: " << g_val << ", &g_val: " << &g_val << endl;

//         sleep(1);
//         i++;
//     }

//     delete td;
//     return nullptr;
// }

// int main()
// {
//     vector<pthread_t> tids;
//     for(int i = 0; i < NUM; i++)
//     {
//         pthread_t tid;
//         pthreadDate* td = new pthreadDate;
//         initThread(td, i);

//         pthread_create(&tid, nullptr, threadRoutine, td);
//         tids.push_back(tid);
//         sleep(1);
//     }

//     // for(auto i : tids)
//     // {
//     //     pthread_detach(i);
//     // }

//     cout << "main thread get a new thread local value, val: " << *p << ", &val: " << p << endl;
//     for(int i = 0; i < NUM; i++)
//     {
//         int n = pthread_join(tids[i], nullptr);
//         printf("n = %d, who = %x, why: %s\n", n, tids[i], strerror(n));
//     }

//     return 0;
// }